home *** CD-ROM | disk | FTP | other *** search
- /*
- * File: balls_pallet.c
- * Author: Eric Van Gestel
- * Updated for X11 by Mark S. Wedel
- *
- * For: xblockbuster
- *
- * Implementation:
- * Drawing is to be done twice with the same coordinates such that
- * the second removes the first while restoring the context.
- * The procedure move_balls is called on timeout (xblockbuster.c)
- * The procedure draw_pallet is called whenever the pallet changes (mouse
- * movement event, button 1 or 2, or hitting a clipper.)
- * Auxilary print functions added by MSW to help clean up the code a
- * little.
- * The auxiliary functions return a boolean value indicating whether
- * the hit might have increased the score.
- */
-
-
- #include "xblockbuster.h"
-
- #include "icons/ball.pr"
-
- static char str[256];
-
-
- void print_score()
- {
- sprintf(str, "Score: %d ", score );
- XDrawImageString(display, win, gc, OFFSET_SCORE, font_height, str,
- strlen(str));
- }
-
- void print_balls()
- {
- sprintf(str, "Balls left: %d ", balls_left);
- XDrawImageString(display, win, gc, OFFSET_BALLS, font_height, str,
- strlen(str));
- }
-
- Pixmap ball_pr;
- extern int in_event, do_balls, timer_active;
-
- void ball_init()
- {
- ball_pr = XCreateBitmapFromData(display, win, ball_bits, ball_width, ball_height);
- }
-
- /* Macro to draw a ball */
-
- #define draw_ball( ball ) \
- XCopyPlane(display, ball_pr, win, gc_xor, 0, 0, 16, 16, \
- (int)( (ball)->x ) - 8, (int)( (ball)->y ) - 8, 1)
-
-
- /* Procedure to draw the pallet */
- void
- draw_pallet( )
- {
- XDrawLine( display, win, gc_xor, pallet_xI - pallet_lengthI + 2, pallet_yI,
- pallet_xI + pallet_lengthI - 2, pallet_yI);
- XDrawLine( display, win, gc_xor, pallet_xI - pallet_lengthI + 1, pallet_yI + 1,
- pallet_xI + pallet_lengthI - 1, pallet_yI + 1);
- XDrawLine( display, win, gc_xor, pallet_xI - pallet_lengthI, pallet_yI + 2,
- pallet_xI + pallet_lengthI, pallet_yI + 2);
- XDrawLine( display, win, gc_xor, pallet_xI - 1, pallet_yI + 3,
- pallet_xI - 1, pallet_yI + 6);
- XDrawLine( display, win, gc_xor, pallet_xI - 1, pallet_yI + 6,
- pallet_xI + 1, pallet_yI + 6);
- XDrawLine( display, win, gc_xor, pallet_xI + 1, pallet_yI + 6,
- pallet_xI + 1, pallet_yI + 3);
- XDrawLine( display, win, gc_xor, 0, mouse_yI - 1, /* <HC> */
- 10, mouse_yI - 1);
- XDrawLine( display, win, gc_xor, 0, mouse_yI,
- 10, mouse_yI);
- XDrawLine( display, win, gc_xor, 0, mouse_yI + 1, /* <HC> */
- 10, mouse_yI + 1);
- XDrawLine( display, win, gc_xor, STAGE_WIDTH_IN_PIXELS - 1, mouse_yI - 1, /* <HC> */
- STAGE_WIDTH_IN_PIXELS - 11, mouse_yI - 1);
- XDrawLine( display, win, gc_xor, STAGE_WIDTH_IN_PIXELS - 1, mouse_yI,
- STAGE_WIDTH_IN_PIXELS - 11, mouse_yI);
- XDrawLine( display, win, gc_xor, STAGE_WIDTH_IN_PIXELS - 1, mouse_yI + 1, /* <HC> */
- STAGE_WIDTH_IN_PIXELS - 11, mouse_yI + 1);
- }
-
-
- /* Procedure to show the speeds */
- #define SX OFFSET_SPEED + 70
- void
- show_speeds( )
- {
- int sp;
-
- XDrawImageString(display, win, gc, OFFSET_SPEED, font_height,
- "Speed: ",16);
-
- /* scale line */
- XDrawLine( display, win, gc, SX, font_height - 1, SX + SPEED_RESOLUTION - 1, font_height - 1);
- XDrawLine( display, win, gc, SX, font_height, SX + SPEED_RESOLUTION, font_height);
- XDrawLine( display, win, gc, SX, font_height + 1, SX + SPEED_RESOLUTION - 1, font_height + 1);
-
- /* base bar */
- XDrawLine( display, win, gc, SX, font_height - 12, SX, font_height + 3);
- XDrawLine( display, win, gc, SX + 1, font_height - 12, SX + 1, font_height + 3);
-
- /* launch speed bar */
- sp = ( int ) ( launch_speed * SPEED_RESOLUTION_FACTOR );
- if ( launch_speed < MAX_SPEED )
- XDrawLine( display, win, gc, SX + sp, font_height - 2, SX + sp, font_height + 2);
- else
- XDrawLine( display, win, gc, SX + sp, font_height - 2, SX + sp, font_height + 2);
-
- /* ball lines */
- if ( ball1.quadrant ) {
- sp = ( int ) ( ball1.speed * SPEED_RESOLUTION_FACTOR );
- XDrawLine( display, win, gc, SX, font_height - 4, SX + sp, font_height - 4);
- }
- if ( ball2.quadrant ) {
- sp = ( int ) ( ball2.speed * SPEED_RESOLUTION_FACTOR );
- XDrawLine( display, win, gc, SX, font_height - 7, SX + sp, font_height - 7);
- }
- if ( ball3.quadrant ) {
- sp = ( int ) ( ball3.speed * SPEED_RESOLUTION_FACTOR );
- XDrawLine( display, win, gc, SX, font_height - 10, SX + sp, font_height - 10);
- }
- }
-
-
-
- /* auxiliary procedures */
- void
- new_ball( ball )
- register struct Ball *ball;
- {
- if ( balls_left-- ) {
- ball->quadrant = launch_quadrant;
- ball->angle = 0.0;
- ball->row = launch_row;
- ball->col = launch_col;
- ball->x = launch_x;
- ball->y = launch_y;
- ball->speed = launch_speed;
- ball->x_speed = launch_speed * ( ( ball->quadrant == NE ) ? M_SQRT2_2
- /* NW */ : -M_SQRT2_2 );
- ball->y_speed = launch_speed * -M_SQRT2_2;
- /* initial ball image */
- draw_ball( ball );
- /* show balls left */
- print_balls();
- /* show speeds */
- show_speeds( );
- } else {
- balls_left = 0; /* kludge */
- XDrawImageString(display, win, gc, 0, font_height,
- "Game Over.",10 );
- sleep( 2 );
- show_score_board( ); /* BYE !! */
- }
- }
-
-
- void
- blow_up( row, col )
- register int row, col;
- {
- if ( stage[row][col].code == ' ' )
- return; /* nothing there */
- if ( IS_HIT_BRICK( stage[row][col].code ) )
- nbricks--;
- stage[row][col].code = 'R';
- draw_brick( row, col );
- }
-
-
- int /* boolean */
- hit_brick( hit, ball )
- register int hit; /* enumeration { HORIZONTAL, VERTICAL } */
- register struct Ball *ball;
- {
- register struct Brick *brick = &stage[ball->row][ball->col];
- register int busted = FALSE;
- register int redraw = FALSE;
- register int score_hit = FALSE;
- char str[80];
-
- /* has the ball left the stage vertically ? */
- if ( ball->row < 0 || ball->row > MAX_ROW ) {
- ball->quadrant = NO_BALL; /* so much for this ball */
- return ( score_hit );
- }
- /* check for looping */
- switch ( brick->code ) {
- case ' ': /* no hit */
- break;
- case '#':
- case '/':
- case '\\':
- case '^':
- case '0':
- case 'A':
- case 'R':
- case 'S':
- case 'U': /* because it may undo another one */
- case 'W':
- case '%':
- if ( !( ++loop_nhits % LOOP_MAX ) )
- ball->x -=
- ball->x_speed * ( double ) ( loop_nhits / LOOP_MAX ) + 1;
- /* horizontal shift, trying to get out of a bounce loop */
- /* negative to try to avoid leaving the stage */
- break;
- default: /* non-solid brick */
- loop_nhits = 0;
- }
-
- /* advance score taking special action if needed */
- switch ( brick->code ) {
- case ' ': /* clear space */
- /* has the ball left the stage horizontally ? */
- if ( ball->col <= 0 || ball->col >= MAX_COL ) {
- ball->quadrant = NO_BALL; /* so much for this ball */
- }
- return ( score_hit ); /* no hit */
-
- case '#': /* solid wall */
- case '/': /* launchpad NE */
- case '\\': /* launchpad NW */
- case '^': /* emitter */
- break;
-
- case '0': /* solid brick */
- score += score_incr;
- score_hit = TRUE;
- break;
-
- case 'A': /* absorber */
- ball->x += ( double ) ( emit_col - ball->col ) * 64;
- ball->y += ( double ) ( emit_row - ball->row ) * 16;
- break;
- case 'C': /* clipper */
- if ( ++( brick->nhits ) == 2 ) {
- draw_pallet();
- pallet_lengthI -= pallet_lengthI / 5;
- if ( pallet_lengthI < MIN_PALLET_LENGTH )
- pallet_lengthI = MIN_PALLET_LENGTH;
- pallet_length = ( double ) pallet_lengthI;
- busted = TRUE;
- draw_pallet();
- }
- break;
- case 'D': /* double */
- if ( ++( brick->nhits ) == 2 ) {
- score_incr *= 2;
- busted = TRUE;
- sprintf(str,"Bonus x%d",score_incr);
- XDrawImageString(display, win, gc,
- OFFSET_SCORE, font_height*2, str,
- strlen(str));
- }
- break;
- case 'E': /* extra ball */
- if ( ++( brick->nhits ) == 2 ) {
- balls_left++;
- print_balls();
- busted = TRUE;
- }
- break;
- case 'G': /* gap */
- if ( ++( brick->nhits ) == 2 ) {
- ball->quadrant = NO_BALL; /* so much for this ball */
- busted = TRUE;
- }
- break;
- case 'H': /* halt */
- if ( ++( brick->nhits ) == 3 )
- busted = TRUE;
- {
- double pause = 0.1 * ( double ) ( 10 - brick->nhits );
-
- ball->speed *= pause;
- ball->x_speed *= pause;
- ball->y_speed *= pause;
- }
- /* approximative; will be corrected on next pallet deflection */
- show_speeds( );
- break;
- case 'I': /* invisible brick */
- score += score_incr;
- brick->code = '1';
- nbricks++;
- score_hit = redraw = TRUE;
- break;
- case 'L': /* launch ball */
- if ( ++( brick->nhits ) == 2 ) {
- balls_left++; /* kludge to avoid consuming a ball */
- if ( !ball1.quadrant )
- new_ball( &ball1 );
- else if ( !ball2.quadrant )
- new_ball( &ball2 );
- else if ( !ball3.quadrant )
- new_ball( &ball3 );
- else
- print_balls();
- show_speeds( );
- busted = TRUE;
- }
- break;
- case 'M': /* mine */
- if ( ++( brick->nhits ) == 3 ) {
- blow_up( ball->row - 1, ball->col - 1 );
- blow_up( ball->row - 1, ball->col );
- blow_up( ball->row - 1, ball->col + 1 );
- blow_up( ball->row, ball->col - 1 );
- blow_up( ball->row, ball->col + 1 );
- blow_up( ball->row + 1, ball->col - 1 );
- blow_up( ball->row + 1, ball->col );
- blow_up( ball->row + 1, ball->col + 1 );
- busted = TRUE;
- }
- break;
- case 'P': /* pause */
- if ( ++( brick->nhits ) == 8 ) {
- launch_speed -= ( launch_speed - INIT_SPEED ) * 0.3;
- busted = TRUE;
- }
- show_speeds( );
- break;
- case 'R': /* refractor */
- ball->angle = -( ball->angle );
- {
- register int sign = ( ball->x_speed * ball->y_speed ) < 0;
- register double tmp = ball->x_speed;
-
- ball->x_speed = sign ? -( ball->y_speed ) : ball->y_speed;
- ball->y_speed = sign ? -tmp : tmp;
- /*
- * note no check for NEAR_HORIZONTAL and none needed
- * since,
- */
- /*
- * if it gets too horizontal, it probably will hit it
- * again.
- */
- }
- return ( FALSE ); /* no deflection */
- case 'S': /* speeder */
- if ( ball->speed < SPEED_LIMIT ) {
- ball->speed += SPEED_INCR;
- ball->x_speed += ( ball->x_speed < 0 ) ? -SPEED_INCR_2
- : SPEED_INCR_2;
- ball->y_speed += ( ball->y_speed < 0 ) ? -SPEED_INCR_2
- : SPEED_INCR_2;
- /*
- * approximative; will be corrected on next pallet
- * deflection
- */
- show_speeds( );
- } else
- pallet_modif++;
- break;
- case 'T': /* triple */
- if ( ++( brick->nhits ) == 3 ) {
- score_incr *= 3;
- busted = TRUE;
- sprintf(str,"Bonus x%d",score_incr);
- XDrawImageString(display, win, gc,
- OFFSET_SCORE, font_height*2, str,
- strlen(str));
- }
- break;
- case 'U': /* undo */ ;
- /* effective only after something has been busted */
- if ( last_busted_brick ) {
- last_busted_brick->code = last_busted_code;
- last_busted_brick->nhits = 0;
- if ( IS_HIT_BRICK( last_busted_code ) )
- nbricks++;
- draw_brick( last_busted_row, last_busted_col );
- busted = TRUE;
- }
- break;
- case 'W': /* open window */ ;
- brick->code = '%';
- /* redraw = TRUE */ draw_brick( ball->row, ball->col );
- return ( score_hit ); /* no deflection */
- case '%': /* closed window */ ;
- brick->code = 'W';
- redraw = TRUE;
- break;
- case 'X': /* expander */
- if ( ++( brick->nhits ) == 4 ) {
- pallet_modif -= 2 * PALLET_INCR;
- busted = TRUE;
- }
- break;
-
- default:
- if ( brick->code >= '1' && brick->code <= '9' ) {
- /* hit bricks */
- score += ++( brick->nhits ) * score_incr;
- score_hit = TRUE;
- if ( brick->nhits == brick->code - '0' )
- busted = TRUE;
- else
- redraw = TRUE;
- } else { /* 'a' .. 'e' & 'j' */
- /* bonus= bricks */
- if ( ++( brick->nhits ) > brick->code - 'a' + 1 ) {
- score += ( brick->code - 'a' + 1 ) * 10 * score_incr;
- score_hit = busted = TRUE;
- }
- }
- }
- if ( busted ) {
- last_busted_brick = brick;
- last_busted_code = brick->code;
- last_busted_row = ball->row;
- last_busted_col = ball->col;
- if ( IS_HIT_BRICK( brick->code ) )
- nbricks--;
- brick->code = ' ';
- redraw = TRUE;
- }
- /* redraw brick (never on the sides) */
- if ( redraw ) {
- if ( pallet_row == ball->row )
- draw_pallet( ); /* avoid shadow */
- draw_brick( ball->row, ball->col );
- if ( pallet_row == ball->row )
- draw_pallet( ); /* restore */
- }
- /* deflection */
- if ( ball->col <= 0 || ball->col >= MAX_COL ) {
- /*
- * kludge to avoid tunnelling out through the side (or
- * corner)
- */
- if ( ( ball->col <= 0 &&
- ( ball->quadrant == NW || ball->quadrant == SW ) ) ||
- ( ball->col >= MAX_COL &&
- ( ball->quadrant == NE || ball->quadrant == SE ) ) )
- brick_deflection( VERTICAL, ball );
- if ( ( ball->row == 0 &&
- ( ball->quadrant == NE || ball->quadrant == NW ) ) ||
- ( ball->row == MAX_ROW &&
- ( ball->quadrant == SE || ball->quadrant == SW ) ) )
- brick_deflection( HORIZONTAL, ball );
- } else
- brick_deflection( hit, ball );
-
- return ( score_hit );
- }
-
- int /* boolean */
- move_ball( ball )
- register struct Ball *ball;
- {
- register int tmp; /* tmp row or col designation */
- register int hit = FALSE; /* enumeration { FALSE, HORIZONTAL,
- * VERTICAL } */
- register int score_hit = FALSE; /* boolean */
-
- /* erase ball image */
- draw_ball( ball );
-
- /* move ball */
- ball->x += ball->x_speed;
- ball->y += ball->y_speed;
-
- /* might it have hit a brick ? */
- if ( ( tmp = X_COL( ball->x ) ) != ball->col ) {
- ball->col = tmp;
- hit = VERTICAL;
- }
- if ( ( tmp = Y_ROW( ball->y ) ) != ball->row ) {
- ball->row = tmp;
- hit = HORIZONTAL; /* HORIZONTAL takes precedence over
- * VERTICAL */
- }
- if ( hit )
- score_hit = hit_brick( hit, ball );
- if ( !ball->quadrant ) {
- /* so much for this ball */
- show_speeds( );
- return ( score_hit );
- }
- /* might it have hit the pallet ? */
- if ( ball->y >= pallet_y - 0.1 && /* round of protection */
- ball->y <= pallet_y + ball->y_speed &&
- ball->x >= pallet_x - pallet_length &&
- ball->x <= pallet_x + pallet_length ) {
- loop_nhits = 0;
- pallet_deflection( ball );
- }
- /* redraw ball image */
- draw_ball( ball );
-
- return ( score_hit );
- }
-
- void check_ball(ball, old_pallet_y)
- register struct Ball *ball;
- double old_pallet_y;
- {
- if ( ball->y >= pallet_y - 0.1 && /* round of protection */
- ball->y <= old_pallet_y + ball->y_speed &&
- ball->x >= pallet_x - pallet_length &&
- ball->x <= pallet_x + pallet_length ) {
- loop_nhits = 0;
- pallet_deflection( ball );
- }
- }
-
- void
- check_deflections(old_pallet_y )
- double old_pallet_y;
- {
- if (ball1.quadrant) check_ball(&ball1,old_pallet_y);
- if (ball2.quadrant) check_ball(&ball3,old_pallet_y);
- if (ball3.quadrant) check_ball(&ball3,old_pallet_y);
- }
-
-
- void draw_balls()
- {
- if ( ball1.quadrant ) draw_ball(&ball1);
- if ( ball2.quadrant ) draw_ball(&ball2);
- if ( ball3.quadrant ) draw_ball(&ball3);
- }
-
-
- /*** on timeout event ***/
- void move_balls( )
- {
- register int score_hit1 = FALSE, score_hit2 = FALSE, score_hit3 = FALSE;
-
- /* start new ball if none left */
- if ( !ball1.quadrant && !ball2.quadrant && !ball3.quadrant ) {
- new_ball( &ball1 );
- }
-
- /* move balls */
- if ( ball1.quadrant )
- score_hit1 = move_ball( &ball1 );
- if ( ball2.quadrant )
- score_hit2 = move_ball( &ball2 );
- if ( ball3.quadrant )
- score_hit3 = move_ball( &ball3 );
-
- /* start new stage if no more bricks to bust */
- if ( nbricks <= 0 ) {
-
- /* add stage bonus */
- score += 100;
-
- XFillRectangle( display,win, gc_erase,
- 0, 0, STAGE_WIDTH_IN_PIXELS - 1, MSG_HEIGHT);
- XDrawImageString(display, win, gc,
- 0,font_height, " Stage bonus: 100",17);
-
-
- /* erase ball images */
- if ( ball1.quadrant ) {
- ball1.quadrant = NO_BALL;
- balls_left++; /* kludge to avoid consuming the ball */
- draw_ball( &ball1 );
- }
- if ( ball2.quadrant ) {
- ball2.quadrant = NO_BALL;
- balls_left++; /* kludge to avoid consuming the ball */
- draw_ball( &ball2 );
- }
- if ( ball3.quadrant ) {
- ball3.quadrant = NO_BALL;
- balls_left++; /* kludge to avoid consuming the ball */
- draw_ball( &ball3 );
- }
- /* update score */
- print_score();
- timer_active=0;
- /* off we go again */
- new_stage( );
-
- } else {
-
- /* update score */
- if ( score_hit1 || score_hit2 || score_hit3 )
- print_score();
-
-
- if (!ball1.quadrant && !ball2.quadrant && !ball3.quadrant) {
- timer_active=0;
- XFlush(display);
- if (balls_left==0) {
- print_balls();
- show_score_board( ); /* BYE !! */
- }
- }
- }
-
- }
-
-
-
-